package com.springboot.config.log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.RequestFacade;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: zyj
 * @create: 2020-12-02 10:22
 **/
@Component
@Slf4j
public class WriteLog {

    @Async("taskExecutor")
    public void writeOut(ProceedingJoinPoint joinPoint, Object result, Map<String, Object> request, long timeConsuming){

        try {
            // ip地址
            Object ipAddr = request.get("ipAddr");
            // 请求路径
            Object requestUrl = request.get("requestUrl");
            // 请求方法
            Object method = request.get("method");
            // 获取请求参数进行打印
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;

            // 类名
            // swagger中文注释名
            String className = "";
            Tag api = methodSignature.getMethod().getDeclaringClass().getAnnotation(Tag.class);
            if(null != api){
                String classCommentName = api.name();
                if(org.apache.commons.lang3.StringUtils.isNotBlank(classCommentName)){
                    String[] sourceName = signature.getDeclaringTypeName().split("\\.");
                    className = sourceName[sourceName.length - 1] + "[" + classCommentName +"]";
                }
            }

            // 方法名
            // swagger中文注释名
            Operation annotation = methodSignature.getMethod().getAnnotation(Operation.class);
            String methodName = "";
            if(null!=annotation){
                methodName = signature.getName() + "[" + annotation.description() + "]";
            }

            // 参数名数组
            String[] parameterNames = ((MethodSignature) signature).getParameterNames();
            // 构造参数组集合
            List<Object> argList = new ArrayList<>();
            for (Object arg : joinPoint.getArgs()) {
                // request/response无法使用toJSON
                if (arg instanceof HttpServletRequest) {
                    argList.add("request");
                } else if (arg instanceof HttpServletResponse) {
                    argList.add("response");
                }else if (arg instanceof MultipartFile) {
                    argList.add("MultipartFile");
                }else if (null == arg ) {
                    argList.add("null");
                } else {
                    argList.add(JSON.toJSON(arg));
                }
            }


            //过滤文件流打印
            try{
                if(result instanceof ResponseEntity){
                    ResponseEntity responseEntity = (ResponseEntity) result;
                    HttpHeaders httpHeaders = responseEntity.getHeaders();
                    if(null!=httpHeaders && !httpHeaders.isEmpty() ){
                        List<String> stringList = httpHeaders.get("Content-Disposition");
                        if( null!=stringList && !httpHeaders.isEmpty() && stringList.get(0).startsWith("attchement;filename=")){
                            result = stringList;
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }


            log.info("请求源IP【{}】方法【{}】 -> 请求URL【{}】" +
                            "\n{} -> {} -> 请求耗时：[{}]毫秒 " +
                            "\n请求参数：{} -> {}" +
                            "\n请求结果：{}",
                    ipAddr,method, requestUrl,
                    className, methodName, timeConsuming,
                    JSON.toJSONString(parameterNames, SerializerFeature.WriteMapNullValue), JSON.toJSONString(argList, SerializerFeature.WriteMapNullValue),
                    JSON.toJSONString(result, SerializerFeature.WriteMapNullValue));
        } catch (Exception e) {
            log.error("参数获取失败: ", e);
        }
    }


    public boolean isJson(String content) {
        if(null == content || content.isEmpty()|| "null".equals(content)){
            return false;
        }
        boolean isJsonObject = true;
        boolean isJsonArray = true;
        try {
            JSONObject.parseObject(content);
        } catch (Exception e) {
            isJsonObject = false;
        }
        try {
            JSONObject.parseArray(content);
        } catch (Exception e) {
            isJsonArray = false;
        }
        if(!isJsonObject && !isJsonArray){ //不是json格式
            return false;
        }
        return true;
    }


}
